package com.xydpeng.rpc.protocol;

import com.xydpeng.rpc.common.compiler.Compiler;
import com.xydpeng.rpc.common.compiler.support.JdkCompiler;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;

/**
 * @author xydpeng
 * @version v1.0
 * @date: 2023/4/10
 * @description:
 */
@Slf4j
public class HandlerMapping {

    private static ServiceConfig[] serviceConfigs = {};
    private static Map<Class, ServiceMeta> serviceMetaMap = new HashMap<>();

    private static final Map<Integer, HandlerMeta> handlerMetaMap = new HashMap<>();

    public static void init(Map<Class, ServiceConfig<?>> serviceConfigMap) {
        HandlerMapping.serviceConfigs = serviceConfigMap.values().toArray(new ServiceConfig[serviceConfigMap.size()]);
        //生成并初始化执行器映射
        for (int i = 0; i < serviceConfigs.length; i++) {
            ServiceConfig sc = serviceConfigs[0];
            ServiceMeta<?> serviceMeta = new ServiceMeta<>(sc.getInterfaceClass(), sc.getRef());
            serviceMetaMap.put(sc.getInterfaceClass(), serviceMeta);
            Map<Integer, HandlerMeta> handlerMetas = serviceMeta.getHandlerMetaMap();
            //检验重复
            for (Integer key : handlerMetas.keySet()) {
                if (handlerMetaMap.containsKey(key)) {
                    throw new IllegalStateException("interfaceClass method methodId has conflicted:" + handlerMetas.get(key).getFullMethodName()
                            + " vs " + handlerMetaMap.get(key).getFullMethodName());
                }
                handlerMetaMap.put(key, handlerMetas.get(key));
            }
        }
        //生成invoker
        HandlerInvokerClassCodeGenerator codeGenerator = new HandlerInvokerClassCodeGenerator();
        Compiler compiler = new JdkCompiler();
        try {
            for (int index = 0; index < serviceConfigs.length; index++) {
                ServiceConfig sc = serviceConfigs[index];

                String code = codeGenerator.generate(sc.getInterfaceClass(), index);
                Class<?> handlerInvokerClz = compiler.compile(HandlerInvoker.class, code, sc.getInterfaceClass().getClassLoader());
                HandlerInvoker invoker = (HandlerInvoker) handlerInvokerClz.newInstance();
                ServiceMeta serviceMeta = serviceMetaMap.get(sc.getInterfaceClass());
                serviceMeta.getHandlerMetaMap().values().forEach(meta -> ((HandlerMeta) meta).setInvoker(invoker));
            }
        } catch (Exception e) {
            log.error("HandlerMapping init", e);
            throw new IllegalStateException(e);
        }
    }

    public static HandlerMeta getHandlerMeta(int handlerId) {
        return handlerMetaMap.get(handlerId);
    }

    public static ServiceMeta getServiceMeta(Class interfaceClass) {
        return serviceMetaMap.get(interfaceClass);
    }


    public static ServiceConfig getServiceConfig(int index) {
        if (index > serviceConfigs.length) {
            return null;
        }
        return serviceConfigs[index];
    }

    public static ServiceConfig[] getServiceConfigs() {
        return serviceConfigs;
    }


    public static Map<Class, ServiceMeta> getServiceMetaMap() {
        return serviceMetaMap;
    }


}
